/*!
 * \file TraderFemas.h
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief Femas交易接口实现
 * 
 * \details Femas交易接口适配器，基于飞马交易系统API实现
 *          提供期货交易的完整功能，支持期货交易、查询等操作
 *          采用异步回调机制，支持多线程安全操作
 */
#pragma once

#define WINVER			0x0501
#define _WIN32_WINNT	0x0501
#define _WIN32_IE		0x0501

#include <string>
#include <queue>
#include <unordered_map>
#include <stdint.h>
#include <atomic>

#include <boost/asio/io_context.hpp>
#include <boost/asio/strand.hpp>

#include "../Includes/WTSTypes.h"
#include "../Includes/ITraderApi.h"
#include "../Share/StdUtils.hpp"
#include "../Includes/WTSVariant.hpp"

//Femas v3.02
#include "../API/Femas3.02/USTPFtdcTraderApi.h"

#include "../Share/DLLHelper.hpp"

USING_NS_WTP;

typedef std::unordered_map<std::string, std::string>	StringMap;

/*!
 * \class TraderFemas
 * \brief Femas交易接口实现类
 * 
 * \details Femas交易接口适配器，继承自ITraderApi和CUstpFtdcTraderSpi
 *          实现WonderTrader统一交易接口，封装Femas API的具体实现
 *          
 *          主要功能：
 *          - Femas交易连接管理：支持前置服务器连接、断线重连
 *          - 用户认证登录：支持用户名密码登录、数字证书认证
 *          - 订单管理：支持订单提交、撤单、改单操作
 *          - 持仓查询：支持持仓查询、持仓明细查询
 *          - 资金查询：支持账户资金查询、保证金计算
 *          - 成交查询：支持历史成交查询、实时成交推送
 *          - 数据转换：WonderTrader数据结构与Femas数据结构互转
 *          - 异步查询：支持多线程异步查询，避免阻塞主线程
 *          - 错误处理：完善的错误处理和异常恢复机制
 *          
 *          Femas特色功能：
 *          - 支持飞马交易系统的特有功能
 *          - 支持数字证书认证
 *          - 支持查询前置和交易前置分离
 *          - 支持在线查询模式
 *          
 * \note 使用前需要先初始化并连接到Femas前置服务器
 * \warning 所有交易操作都是异步的，结果通过回调函数返回
 * \see ITraderApi, CUstpFtdcTraderSpi
 */
class TraderFemas : public ITraderApi, public CUstpFtdcTraderSpi
{
public:
	TraderFemas();
	virtual ~TraderFemas();

public:
	/*!
	 * \enum WrapperState
	 * \brief 交易接口状态枚举
	 * 
	 * \details 定义Femas交易接口的各种连接和登录状态
	 */
	typedef enum 
	{
		WS_NOTLOGIN,		///< 未登录状态
		WS_LOGINING,		///< 正在登录状态
		WS_LOGINED,			///< 已登录状态
		WS_LOGINFAILED,		///< 登录失败状态
		WS_CONFIRM_QRYED,	///< 结算单查询状态
		WS_CONFIRMED,		///< 结算单确认状态
		WS_ALLREADY			///< 全部就绪状态，可以进行交易
	} WrapperState;

private:
	/*!
	 * \brief 初始化完成回调
	 * 
	 * \details 当Femas API初始化完成后调用
	 *          开始连接流程
	 */
	void onInitialized();

	/*!
	 * \brief 用户认证
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 向Femas服务器发送用户认证请求
	 *          使用数字证书进行认证
	 */
	int authenticate();

	/*!
	 * \brief 执行用户登录
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 向Femas服务器发送用户登录请求
	 *          使用用户名和密码进行身份验证
	 */
	int doLogin();

//////////////////////////////////////////////////////////////////////////
//ITraderApi接口实现
public:
	/*!
	 * \brief 初始化Femas交易接口
	 * \param params 初始化参数
	 * \return 成功返回true，失败返回false
	 * 
	 * \details 初始化Femas交易接口，设置连接参数
	 *          必需参数：
	 *          - front: 交易前置服务器地址
	 *          - qryfront: 查询前置服务器地址
	 *          - broker: 经纪商代码
	 *          - user: 用户名
	 *          - pass: 密码
	 *          
	 *          可选参数：
	 *          - appid: 应用程序标识
	 *          - authcode: 认证码
	 *          - flowdir: 流文件目录
	 *          - femasmodule: Femas动态库模块名
	 *          - quick: 是否快速启动
	 *          - qryonline: 是否在线查询
	 */
	virtual bool init(WTSVariant* params);

	/*!
	 * \brief 释放Femas交易接口资源
	 * 
	 * \details 清理所有资源，断开连接，停止工作线程
	 *          释放Femas API对象，清理数据缓存
	 */
	virtual void release();

	/*!
	 * \brief 设置标签
	 * \param tag 标签字符串
	 * 
	 * \details 设置交易接口的标识标签
	 */
	virtual void setTag(const char* tag){m_strTag = tag;}

	/*!
	 * \brief 获取标签
	 * \return 标签字符串
	 * 
	 * \details 获取交易接口的标识标签
	 */
	virtual const char* getTag(){return m_strTag.c_str();}

	/*!
	 * \brief 注册交易事件监听器
	 * \param listener 事件监听器指针
	 * 
	 * \details 设置交易事件的回调处理器
	 *          用于接收交易相关的事件通知
	 */
	virtual void registerSpi( ITraderSpi *listener );

	/*!
	 * \brief 生成委托单号
	 * \param buffer 输出缓冲区
	 * \param length 缓冲区长度
	 * \return 成功返回true，失败返回false
	 * 
	 * \details 生成唯一的委托单号标识
	 *          格式：会话ID#本地订单号
	 */
	virtual bool makeEntrustID(char* buffer, int length);

	/*!
	 * \brief 连接到Femas服务器
	 * 
	 * \details 建立与Femas交易前置服务器的连接
	 *          启动异步查询工作线程
	 */
	virtual void connect();

	/*!
	 * \brief 断开与Femas服务器的连接
	 * 
	 * \details 安全断开连接并清理资源
	 *          停止工作线程，释放API对象
	 */
	virtual void disconnect();

	/*!
	 * \brief 检查连接状态
	 * \return 已连接返回true，未连接返回false
	 * 
	 * \details 检查与Femas服务器的连接状态
	 */
	virtual bool isConnected();

	/*!
	 * \brief 用户登录
	 * \param user 用户名
	 * \param pass 密码
	 * \param productInfo 产品信息
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 启动用户登录流程
	 *          先进行数字证书认证，再进行用户登录
	 */
	virtual int login(const char* user, const char* pass, const char* productInfo);

	/*!
	 * \brief 用户登出
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 向Femas服务器发送用户登出请求
	 */
	virtual int logout();

	/*!
	 * \brief 提交订单
	 * \param eutrust 委托单对象
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 向Femas服务器提交交易订单
	 *          支持限价单、市价单等多种订单类型
	 */
	virtual int orderInsert(WTSEntrust* eutrust);

	/*!
	 * \brief 订单操作（撤单/改单）
	 * \param action 订单操作对象
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 对已提交的订单进行撤单或改单操作
	 */
	virtual int orderAction(WTSEntrustAction* action);

	/*!
	 * \brief 查询资金账户
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 查询投资者资金账户信息
	 *          包括可用资金、保证金、盈亏等
	 */
	virtual int queryAccount();

	/*!
	 * \brief 查询持仓信息
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 查询投资者持仓信息
	 *          包括持仓数量、持仓成本、浮动盈亏等
	 */
	virtual int queryPositions();

	/*!
	 * \brief 查询订单信息
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 查询当日所有订单信息
	 *          包括已成交、部分成交、未成交订单
	 */
	virtual int queryOrders();

	/*!
	 * \brief 查询成交信息
	 * \return 成功返回0，失败返回错误码
	 * 
	 * \details 查询当日所有成交信息
	 *          包括成交价格、成交数量、成交时间等
	 */
	virtual int queryTrades();

//////////////////////////////////////////////////////////////////////////
//Femas交易接口回调实现
public:
	/*!
	 * \brief 前置连接成功回调
	 * 
	 * \details 当与Femas交易前置服务器连接成功时调用
	 *          开始用户认证流程
	 */
	virtual void OnFrontConnected() override;

	/*!
	 * \brief 查询前置连接成功回调
	 * 
	 * \details 当与Femas查询前置服务器连接成功时调用
	 */
	virtual void OnQryFrontConnected() override;

	/*!
	 * \brief 前置连接断开回调
	 * \param nReason 断开原因
	 * 
	 * \details 当与Femas交易前置服务器连接断开时调用
	 *          更新连接状态，通知上层应用
	 */
	virtual void OnFrontDisconnected(int nReason) override;

	/*!
	 * \brief 查询前置连接断开回调
	 * \param nReason 断开原因
	 * 
	 * \details 当与Femas查询前置服务器连接断开时调用
	 */
	virtual void OnQryFrontDisconnected(int nReason) override;

	/*!
	 * \brief 心跳警告回调
	 * \param nTimeLapse 距离上次心跳的时间间隔
	 * 
	 * \details 当心跳超时时调用，记录警告信息
	 */
	virtual void OnHeartBeatWarning(int nTimeLapse) override;

	/*!
	 * \brief 错误响应回调
	 * \param pRspInfo 错误信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理Femas API返回的错误信息
	 */
	virtual void OnRspError(CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 用户登录响应回调
	 * \param pRspUserLogin 登录响应信息
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理用户登录响应，保存会话信息
	 */
	virtual void OnRspUserLogin(CUstpFtdcRspUserLoginField *pRspUserLogin, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 查询前置系统用户登录响应回调
	 * \param pRspUserLogin 登录响应信息
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理查询前置用户登录响应
	 */
	virtual void OnRspQueryUserLogin(CUstpFtdcRspUserLoginField *pRspUserLogin, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 用户登出响应回调
	 * \param pRspUserLogout 登出信息
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理用户登出响应，更新登录状态
	 */
	virtual void OnRspUserLogout(CUstpFtdcRspUserLogoutField *pRspUserLogout, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 数字证书用户认证响应回调
	 * \param pDSUserCertRspData 认证响应数据
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理数字证书用户认证响应
	 */
	virtual void OnRspDSUserCertification(CUstpFtdcDSUserCertRspDataField *pDSUserCertRspData, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 成交回报推送
	 * \param pTrade 成交信息
	 * 
	 * \details 接收Femas推送的成交通知
	 *          实时更新持仓和资金，通知上层应用
	 */
	virtual void OnRtnTrade(CUstpFtdcTradeField *pTrade) override;

	/*!
	 * \brief 订单回报推送
	 * \param pOrder 订单信息
	 * 
	 * \details 接收Femas推送的订单状态变化通知
	 *          实时更新订单状态，通知上层应用
	 */
	virtual void OnRtnOrder(CUstpFtdcOrderField *pOrder) override;

	/*!
	 * \brief 订单录入响应回调
	 * \param pInputOrder 输入订单信息
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理订单提交响应，通知上层应用订单状态
	 */
	virtual void OnRspOrderInsert(CUstpFtdcInputOrderField *pInputOrder, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 订单操作响应回调
	 * \param pOrderAction 订单操作信息
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理订单操作响应，通知上层应用操作结果
	 */
	virtual void OnRspOrderAction(CUstpFtdcOrderActionField *pOrderAction, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 成交查询响应回调
	 * \param pTrade 成交信息
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理成交查询响应，转换为WonderTrader格式
	 */
	virtual void OnRspQryTrade(CUstpFtdcTradeField *pTrade, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 订单查询响应回调
	 * \param pOrder 订单信息
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理订单查询响应，转换为WonderTrader格式
	 */
	virtual void OnRspQryOrder(CUstpFtdcOrderField *pOrder, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 投资者账户查询响应回调
	 * \param pRspInvestorAccount 投资者账户信息
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理投资者账户查询响应，转换为WonderTrader格式
	 */
	virtual void OnRspQryInvestorAccount(CUstpFtdcRspInvestorAccountField *pRspInvestorAccount, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 投资者持仓查询响应回调
	 * \param pRspInvestorPosition 投资者持仓信息
	 * \param pRspInfo 响应信息
	 * \param nRequestID 请求ID
	 * \param bIsLast 是否最后一条
	 * 
	 * \details 处理投资者持仓查询响应，转换为WonderTrader格式
	 */
	virtual void OnRspQryInvestorPosition(CUstpFtdcRspInvestorPositionField *pRspInvestorPosition, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

	/*!
	 * \brief 订单录入错误回报
	 * \param pInputOrder 输入订单信息
	 * \param pRspInfo 错误信息
	 * 
	 * \details 接收Femas推送的订单提交错误通知
	 */
	virtual void OnErrRtnOrderInsert(CUstpFtdcInputOrderField *pInputOrder, CUstpFtdcRspInfoField *pRspInfo) override;

	/*!
	 * \brief 订单操作错误回报
	 * \param pOrderAction 订单操作信息
	 * \param pRspInfo 错误信息
	 * 
	 * \details 接收Femas推送的订单操作错误通知
	 */
	virtual void OnErrRtnOrderAction(CUstpFtdcOrderActionField *pOrderAction, CUstpFtdcRspInfoField *pRspInfo) override;

protected:
	/*!
	 * \brief 检查响应信息是否包含错误
	 * \param pRspInfo 响应信息
	 * \return 有错误返回true，无错误返回false
	 * 
	 * \details 检查Femas API返回的响应信息中是否包含错误
	 */
	bool IsErrorRspInfo(CUstpFtdcRspInfoField *pRspInfo);

	// 数据类型转换函数（WonderTrader -> Femas）
	int wrapPriceType(WTSPriceType priceType, bool isCFFEX = false);		///< 转换价格类型
	int wrapDirectionType(WTSDirectionType dirType, WTSOffsetType offType);	///< 转换方向类型
	int wrapOffsetType(WTSOffsetType offType);								///< 转换开平类型
	int	wrapTimeCondition(WTSTimeCondition timeCond);						///< 转换时间条件
	int wrapActionFlag(WTSActionFlag actionFlag);							///< 转换操作标志

	const char* wrapExchg(const char* exchg);								///< 转换交易所代码

	// 数据类型转换函数（Femas -> WonderTrader）
	WTSPriceType		wrapPriceType(TUstpFtdcPriceType priceType);		///< 转换价格类型
	WTSDirectionType	wrapDirectionType(TUstpFtdcDirectionType dirType, TUstpFtdcOffsetFlagType offType);	///< 转换方向类型
	WTSDirectionType	wrapPosDirection(TUstpFtdcDirectionType dirType);	///< 转换持仓方向
	WTSOffsetType		wrapOffsetType(TUstpFtdcOffsetFlagType offType);	///< 转换开平类型
	WTSTimeCondition	wrapTimeCondition(TUstpFtdcTimeConditionType timeCond);	///< 转换时间条件
	WTSOrderState		wrapOrderState(TUstpFtdcOrderStatusType orderState);	///< 转换订单状态
	
	// 数据对象创建函数
	WTSOrderInfo*	makeOrderInfo(CUstpFtdcOrderField* orderField);			///< 创建订单信息对象
	WTSEntrust*		makeEntrust(CUstpFtdcInputOrderField *entrustField);	///< 创建委托对象
	WTSError*		makeError(CUstpFtdcRspInfoField* rspInfo);				///< 创建错误对象
	WTSTradeInfo*	makeTradeRecord(CUstpFtdcTradeField *tradeField);		///< 创建成交记录对象

	/*!
	 * \brief 生成请求ID
	 * \return 唯一的请求ID
	 * 
	 * \details 生成Femas API调用的请求标识，确保线程安全
	 */
	uint32_t		genRequestID();

	/*!
	 * \brief 生成本地订单号
	 * \return 唯一的本地订单号
	 * 
	 * \details 生成本地订单标识，用于订单跟踪
	 */
	uint32_t		genLocalOrdID();

	/*!
	 * \brief 触发查询操作
	 * 
	 * \details 触发异步查询队列中的查询操作
	 */
	void			triggerQuery();

protected:
	// 连接配置参数
	std::string		m_strBroker;	///< 经纪商代码
	std::string		m_strFront;		///< 交易前置服务器地址
	std::string		m_strQryFront;	///< 查询前置服务器地址

	std::string		m_strUser;		///< 用户名
	std::string		m_strPass;		///< 密码
	std::string		m_strAppID;		///< 应用程序标识
	std::string		m_strAuthCode;	///< 认证码
	std::string		m_strFlowDir;	///< 流文件目录

	bool			m_bQuickStart;	///< 是否快速启动

	std::string		m_strTag;		///< 标签

	std::string		m_strUserName;	///< 用户名称

	// 回调和管理对象
	ITraderSpi*	m_sink;				///< 交易事件监听器
	uint64_t		m_uLastQryTime;	///< 上次查询时间

	long			m_lDate;		///< 交易日

	// 会话信息
	std::atomic<uint32_t>		m_uLocalOrdID;		///< 本地订单号
	std::string					m_strSessionID;		///< 会话ID

	WrapperState				m_wrapperState;		///< 接口状态

	// Femas API对象
	CUstpFtdcTraderApi*			m_pUserAPI;			///< Femas交易API对象
	std::atomic<uint32_t>		m_iRequestID;		///< 请求ID计数器

	StringMap					m_mapOrderTag;		///< 订单标签映射

	// 数据缓存
	WTSArray*					m_ayPosition;		///< 持仓数组
	WTSArray*					m_ayTrades;			///< 成交数组
	WTSArray*					m_ayOrders;			///< 订单数组
	WTSArray*					m_ayPosDetail;		///< 持仓明细数组
	
	IBaseDataMgr*				m_bdMgr;			///< 基础数据管理器

	// 查询和线程管理
	bool						m_bQryOnline;		///< 是否在线查询
	bool						m_bStopped;			///< 停止标志

	boost::asio::io_context		m_asyncIO;			///< 异步IO上下文
	boost::asio::io_context::strand*	m_strandIO;	///< IO串行化对象
	StdThreadPtr				m_thrdWorker;		///< 工作线程

	// 异步查询管理
	typedef std::queue<CommonExecuter>	QueryQue;
	QueryQue				m_queQuery;			///< 查询队列
	bool					m_bInQuery;			///< 是否正在查询
	StdUniqueMutex		m_mtxQuery;			///< 查询互斥锁
	uint64_t				m_lastQryTime;		///< 上次查询时间

	// 动态库管理
	std::string		m_strModule;			///< 模块路径
	DllHandle		m_hInstCTP;				///< Femas动态库句柄
	typedef CUstpFtdcTraderApi* (*APICreator)(const char *);
	APICreator		m_funcCreator;			///< Femas API创建函数
};

